#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
//
//int main()
//{
//	int a = 0;
//	int b = 0;
//	
//	scanf("%d%d", &a, &b);
//
//	int c = a + b;
//
//	printf("%d\n", c);
//	return 0;
//}

//写一个加法函数，完成2个整形变量的加法操作

//int Add(int x, int y)
//{
//	return x + y;
//}
//
//
//int main()
//{
//	int a = 0;
//	int b = 0;
//	scanf("%d%d", &a, &b);
//	int c = Add(a, b);//函数的调用（使用函数）
//	printf("%d\n", c);
//	return 0;
//}

//void print(void)
//{
//	printf("hehe\n");
//}
//
//int main()
//{
//	print();
//	print();
//	print();
//	return 0;
//}



//int Add(int x, int y)//在函数名Add后的括号中写的x和y,成为形式参数，简称形参
//                     //为什么叫形式参数呢，实际上，如果只是定义了Add函数，而不去调用的话，Add函数的参数x和y也只是形式上存在的
//	                 //不会向内存申请空间，不会真实存在的，所以叫形式参数
//	                 //形式参数只有在函数被调用的过程中为了存放实参传过来的值，才会向内存申请空间，这个过程就是形参的实例化
//
//{
//	return x + y;
//}
//
//int main()
//{
//	int a = 0;
//	int b = 0;
//	
//	scanf("%d%d", &a, &b);
//	
//	int c = Add(a, b);//调用Add函数时，传递给函数的参数a和b
//	                  //被称为实际参数，简称实参，就是真是传给函数的参数
//	
//
//	printf("%d\n", c);
//	return 0;
////}
//
// 
// return 后面可以什么都没有，直接写return0，这种写法适合满足某些条件时候，想提前结束函数
// 
//void test(int n)
//{
//	if (n <= 0)
//		return;
//	int i = 0;
//	int sum = 0;
//	for (i = 1; i <= n; i++)
//	{
//		sum += i;
//	}
//	printf("%d\n", sum);
//}
//
//
//int main()
//{
//    test(5);
//	return 0;
//}

//return返回的值和函数返回类型不一致的时候，系统会自动将返回的值隐式转换为函数的返回值

//int test()
//{
//	return 3.14;
//}
//
//int main()
//{
//	int r = test();
//	
//	printf("%d\n", r);//3
//
//	return 0;
//}

//函数用来判断n是奇数还是偶数
//是奇数返回1
//是偶数返回0
//test(int x)
//{
//	if (x % 2 == 0)
//	{
//		return 0;
//	}
//	else
//	{
//		return 1;
//	}
//}
//
//int main()
//{
//	int n = 0;
//	
//	scanf("%d", &n);
//	
//	int ret = test(n);
//
//	printf("%d\n", ret);
//	
//	return 0;
//}

//在使用函数解决问题的时候，也会将数组作为参数传给函数，在函数内部对数组进行操作
//例：写一个函数对一个整型数组的内容，全部置为-1，再写一个函数打印数组的内容

//void set_arr(int arr2[], int sz2)
//{
//	int i = 0;
//	for (i = 0; i < sz2; i++)
//	{
//		arr2[i] = -1;
//	}
//}
//
//print_arr(int arr2[], int sz2)
//{
//	int i = 0;
//	for (i = 0; i < sz2; i++)
//	{
//		printf("%d ", arr2[i]);
//	}
//	printf("\n");
//}
//
//
//int main()
//{
//	int arr1[10] = {0};
//	int sz1 = sizeof(arr1) / sizeof(arr1[0]);
//	
//	print_arr(arr1, sz1);//print_arr函数与set_arr函数相同，也需要两个实参
//
//	set_arr(arr1, sz1);//set_arr函数能够对数组内容进行设置，需要把数组当作参数传递给函数
//	          //同时函数内部在设置数组的每个元素的时候，也得遍历数组，需要知道数组的元素个数
//	          //所以需要给set_arr传递2个参数，一个是数组，一个是元素个数
//
//	print_arr(arr1, sz1);//print_arr函数与set_arr函数相同，也需要两个实参
//
//	return 0;
//}

//数组传参的重要知识点：
// 1.函数的形参和函数的实参的个数要匹配
// 2.函数的实参是数组，形参也要写成数组形式
// 3.形参如果是一维数组，数组的大小可以省略不写
// 4.形参如果是二维数组，数组的行大小可以省略，列不可以省略
// 5.！！！数组传参，形参是不会创建新的数组的
// 6.形参操作的数组和实参的数组是同一个数组
//

//函数的嵌套调用就是函数之间的互相调用
// 
//假设我们计算某年某月是多少天
//1   2   3  4   5   6    7  8   9  10   11  12
//30  28 31  30  31  30   31 30  31  30  31  30
//    29
//
//int is_leap_year(int year)
//{
//	if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
//	{
//		return 1;
//	}
//	else
//	{
//		return 0;
//	}
//}
//
//int get_days_of_month(int year, int month)
//{
//	//int days[] = { 30, 28, 31, 30, 31, 30, 31, 30, 31, 30, 31,  30 };
//	//             1    2   3  4    5   6   7   8   9   10  11  12
//	//但1月对应在数组下标是0，所以可以有一些小改动
//	int days[] = { 0, 30, 28, 31, 30, 31, 30, 31, 30, 31, 30, 31,  30 };
//	//             0   1    2   3  4    5   6   7   8   9   10
//   //在数组最前面加一个0来表示数组下标为0的位置，使得1月即对应下标1
//	int day = days[month];
//
//	if (is_leap_year(year) && 2 == month)
//	{
//		day += 1;
//	}
//	return day;
//
//}
//
//int main()
//{
//	int year = 0;
//	int month = 0;
//	int ret = scanf("%d %d", &year, &month);
//
//	int days = get_days_of_month(year, month);
//	printf("%d\n", days);
//	return 0;
//}

//函数之间可以嵌套调用，但是不可以嵌套定义！！！

//链式访问就是将一个函数的返回值作为另一个函数的参数，像链条一样将函数串起来
#include <string.h>

//int main()
//{
//	printf("%d\n", strlen("abcdef"));
//
//	return 0;
//}


//有趣的链式访问的例子
// 
//int main()
//{
//
//	printf("%d", printf("%d", printf("%d", 43)));
//	//printf函数可以实现在屏幕上打印字符
//	//但是，printf函数也是又返回值的，printf函数返回的是在屏幕上打印字符的个数
//	//上面例子中，第三个printf打印43，打印了2个字符，返回值是2，第二个printf打印2，打印了1个字符，返回值是1，所以第一个printf打印1
//	//所以结果是4321
//	return 0;
//}

//如果将函数的定义放在调用的后边，就会报错
//怎么解决问题呢，就是在函数调用之前声明一下函数
//声明函数只要交代清楚：函数名，函数的返回类型，函数的参数即可
//函数的调用，一定是先声明，后使用！！！
//函数的定义是一种特殊的声明，所以把函数的定义放在调用之前也是可以的！！！

#include <stdio.h>
#include "add.h"//自定义函数用双引号包含


//int main()
//{
//	int a = 0;
//	int b = 0;
//	scanf("%d %d", &a, &b);
//	int c = Add(a, b);
//	printf("%d\n", c);
//	return 0;
//}

//static和extern
//static是静态的意思，可以用来
//1.修饰局部变量
//2.修饰全局变量
//3.修饰函数



//static修饰局部变量
#include <stdio.h>
//
//void test()
//{
//	int n = 0;
//	n++;
//	printf("%d ", n);
//}
//int main()
//{
//	int i = 0;
//	for (i = 0; i < 5; i++)
//	{
//		test();// 1 1 1 1 1
//		//该代码中的局部变量i是每次进入test函数先创建变量（生命周期开始），并赋值为0，然后++，再打印，
//		// 出函数的时候变量生命周期将要结束（释放内存）所以每次都是打印 1
//	}
//	return 0;
//}

//void test()
//{
//	static int n = 0;
//	n++;
//	printf("%d ", n);
//}
//
//int main()
//{
//	int i = 0;
//	for (i = 0; i < 5; i++)
//	{
//		test();//1 2 3 4 5 
//		       //这段代码中，n的值是有累加效果的，test函数中的n创建好之后，出函数是不会销毁的，
//			   // 重新进入函数也就不会创建新的变量，直接上次累积的数值继续计算
//	}
//	return 0;
//}

//总结：static修饰局部变量改变了变量的生命周期，生命周期改变的本质是改变了变量的存储类型
//本来一个局部变量是存储在内存的栈区的，但是被static修饰后存储到了静态区，存储在静态区的变量是和全局变量一样的
//生命周期和程序的生命周期一样，只有程序结束了，变量才会销毁
//使用建议：一个变量出了函数，还想保留值，等下次进入函数继续使用，就可以使用static修饰局部变量
